﻿//-----------------------------------------------------------------------
// <copyright file="DoNotThrowNotImplementedException.cs">
//     Copyright (c) Nicole Calinoiu. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
using System;
using System.Diagnostics.CodeAnalysis;

using Microsoft.FxCop.Sdk;
using Microsoft.VisualStudio.CodeAnalysis.Extensibility;

using Bordecal.FxCop.Sdk;

namespace Bordecal.FxCop.Rules.Usage
{
	/// <summary>
	/// Rule that verifies that <see cref="NotImplementedException"/> is not thrown.
	/// </summary>
	internal sealed class DoNotThrowNotImplementedException : IntrospectionRule
	{
		#region Constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="DoNotThrowNotImplementedException"/> class.
		/// </summary>
		public DoNotThrowNotImplementedException()
			: base(RuleDescriptorFactory.CreateSingleResolutionDescriptor<DoNotThrowNotImplementedException>(
				RuleCategory.Usage,
				"Do not throw NotImplementedException",
				"Do not throw System.NotImplementedException in production code.",
				95,
				FixCategories.NonBreaking,
				MessageLevel.Warning,
				"Implement the {0} method or throw an exception other than NotImplementedException."))
		{
		}

		#endregion

		#region Properties

		private Method FocalMethod { get; set; }

		#endregion

		#region Methods

		/// <summary>
		/// Verifies compliance of a type member with the implemented rule.
		/// </summary>
		/// <param name="member">The target member.</param>
		/// <returns>A collection of found problems.</returns>
		public override ProblemCollection Check(Member member)
		{
			Method method = member as Method;
			if (method != null)
			{
				this.FocalMethod = method;
				this.VisitBlock(method.Body);
			}

			return this.Problems;
		}

		/// <summary>
		/// Visits a <see cref="ThrowNode"/>.
		/// </summary>
		/// <param name="throwInstruction">The <see cref="ThrowNode"/>.</param>
		public override void VisitThrow(ThrowNode throwInstruction)
		{
			if (throwInstruction == null)
			{
				throw new ArgumentNullException("throwInstruction");
			}

			base.VisitThrow(throwInstruction);

			if ((throwInstruction.NodeType == NodeType.Throw) && (throwInstruction.Expression.Type == Types.NotImplementedException))
			{
				this.AddProblem(throwInstruction, this.FocalMethod);
			}
		}

		#endregion
	}
}